package com.sky.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sky.entity.OrderDetail;
import com.sky.entity.Orders;
import com.sky.entity.User;
import com.sky.service.*;
import com.sky.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

@Service
@Slf4j
public class ReportServiceImpl implements ReportService {

    @Autowired
    private UserService userService;

    @Autowired
    private OrdersService ordersService;

    @Autowired
    private OrderDetailService orderDetailService;

    @Autowired
    private WorkspaceService workspaceService;


    @Override
    public TurnoverReportVO getTurnoverStatistics(LocalDate dateBegin, LocalDate dateEnd) {
        // 存放全部日期
        List<LocalDate> localDateList = new ArrayList<>();
        for (LocalDate date = dateBegin; !date.isAfter(dateEnd); date = date.plusDays(1)) {
            localDateList.add(date);
        }

        // 存放营业额数据
        List<BigDecimal> turnoverList = new ArrayList<>();

        // 查询每日营业额
        for (LocalDate date : localDateList) {
            // 查询 date 当日订单数据，即状态为已完成的订单的金额合计
            List<Orders> ordersList = ordersService.list(
                    new LambdaQueryWrapper<Orders>()
                            .eq(Orders::getStatus, Orders.COMPLETED)
                            .between(Orders::getOrderTime, LocalDateTime.of(date, LocalTime.MIN), LocalDateTime.of(date, LocalTime.MAX))
            );

            BigDecimal turnover = new BigDecimal(0);
            for (Orders orders : ordersList) {
                turnover = turnover.add(orders.getAmount());
            }

            turnoverList.add(turnover);
        }

        return TurnoverReportVO
                .builder()
                .dateList(StringUtils.join(localDateList, ","))
                .turnoverList(StringUtils.join(turnoverList, ","))
                .build();
    }

    @Override
    public UserReportVO getUserStatistics(LocalDate dateBegin, LocalDate dateEnd) {

        // 存放全部日期
        List<LocalDate> localDateList = new ArrayList<>();
        for (LocalDate date = dateBegin; !date.isAfter(dateEnd); date = date.plusDays(1)) {
            localDateList.add(date);
        }

        // 存放每日用户数量
        List<Integer> totalUserList = new ArrayList<>();
        List<Integer> newUserList = new ArrayList<>();

        Integer totalUserNum = 0;
        Integer newUserNum = 0;
        for (LocalDate date : localDateList) {
            // 查询指定日期的全部用户
            List<User> userList = userService.list(
                    new LambdaQueryWrapper<User>()
                            .between(User::getCreateTime, LocalDateTime.of(date, LocalTime.MIN), LocalDateTime.of(date, LocalTime.MAX))
            );

            // 统计用户数量
            newUserNum = userList.size();
            totalUserNum = totalUserNum + newUserNum;

            // 加入列表
            totalUserList.add(totalUserNum);
            newUserList.add(newUserNum);
        }


        return UserReportVO
                .builder()
                .dateList(StringUtils.join(localDateList, ","))
                .totalUserList(StringUtils.join(totalUserList, ","))
                .newUserList(StringUtils.join(newUserList, ","))
                .build();
    }

    @Override
    public OrderReportVO getOrderStatistics(LocalDate dateBegin, LocalDate dateEnd) {

        // 存放全部日期
        List<LocalDate> localDateList = new ArrayList<>();
        for (LocalDate date = dateBegin; !date.isAfter(dateEnd); date = date.plusDays(1)) {
            localDateList.add(date);
        }

        // 存放每日订单数量
        List<Integer> orderCountList = new ArrayList<>();
        List<Integer> validOrderCountList = new ArrayList<>();
        // 订单总数
        Integer totalOrderCount = 0;
        Integer validOrderCount = 0;

        for (LocalDate date : localDateList) {
            // 查询当日订单总数
            List<Orders> orderList = ordersService.list(
                    new LambdaQueryWrapper<Orders>()
                            .between(Orders::getOrderTime, LocalDateTime.of(date, LocalTime.MIN), LocalDateTime.of(date, LocalTime.MAX))
            );
            // 查询当日有效订单总数
            List<Orders> validOrderList = ordersService.list(
                    new LambdaQueryWrapper<Orders>()
                            .eq(Orders::getStatus, Orders.COMPLETED)
                            .between(Orders::getOrderTime, LocalDateTime.of(date, LocalTime.MIN), LocalDateTime.of(date, LocalTime.MAX))
            );

            // 存放当日订单数据
            orderCountList.add(orderList.size());
            validOrderCountList.add(validOrderList.size());

            totalOrderCount = totalOrderCount + orderList.size();
            validOrderCount = validOrderCount + validOrderList.size();

        }


        return OrderReportVO
                .builder()
                .dateList(StringUtils.join(localDateList, ","))
                .orderCountList(StringUtils.join(orderCountList, ","))
                .validOrderCountList(StringUtils.join(validOrderCountList, ","))
                .totalOrderCount(totalOrderCount)
                .validOrderCount(validOrderCount)
                .orderCompletionRate((validOrderCount / (double) totalOrderCount))
                .build();
    }

    @Override
    public SalesTop10ReportVO getSalesTopTen(LocalDate dateBegin, LocalDate dateEnd) {

        // 查询全部订单详细信息
        List<OrderDetail> orderDetailAllList = orderDetailService.list();

        // 存放符合条件的订单详细数据
        List<OrderDetail> orderDetailList = new ArrayList<>();

        // 将符合条件的数据存入列表
        for (OrderDetail orderDetail : orderDetailAllList) {
            // 订单 id
            Long orderId = orderDetail.getOrderId();
            // 查询订单数据
            Orders order = ordersService.getById(orderId);

            // 判断订单是否符合条件：订单已完成且在指定时间内
            if (Objects.equals(order.getStatus(), Orders.COMPLETED)
                    && order.getOrderTime().isAfter(LocalDateTime.of(dateBegin, LocalTime.MIN))
                    && order.getOrderTime().isBefore(LocalDateTime.of(dateEnd, LocalTime.MAX))) {
                // 订单符合条件，存入列表
                orderDetailList.add(orderDetail);
            }

        }

        // 存放菜品和对应的销量信息
        Map<String, Integer> salesMap = new HashMap<>();
        for (OrderDetail orderDetail : orderDetailList) {
            String name = orderDetail.getName();
            Integer num = orderDetail.getNumber();

            if (salesMap.containsKey(name)) {
                // 如果已经存在菜品，则更新销量
                salesMap.put(name, salesMap.get(name) + num);
            } else {
                // 不存在，则直接插入
                salesMap.put(name, num);
            }
        }

        // 将得到的符合条件的菜品进行排序，取 top 10
        Map<String, Integer> sortedSalesMap = sortMap(salesMap, 10);
        // 分别将菜品的名称和销量存入列表
        List<String> nameList = new ArrayList<>(sortedSalesMap.keySet());
        List<Integer> numList = new ArrayList<>(sortedSalesMap.values());

        return SalesTop10ReportVO
                .builder()
                .nameList(StringUtils.join(nameList, ","))
                .numberList(StringUtils.join(numList, ","))
                .build();
    }

    @Override
    public void exportBusinessData(HttpServletResponse response, LocalDate dateBegin, LocalDate dateEnd) {
        // 查询营业数据
        BusinessDataVO businessDataVO = workspaceService.getBusinessData(LocalDateTime.of(dateBegin, LocalTime.MIN), LocalDateTime.of(dateEnd, LocalTime.MAX));

        // 写入文件
        InputStream in = this.getClass().getClassLoader().getResourceAsStream("template/DataReportTemplate.xlsx");
        try {
            // 基于模板文件，创建新的 excel 文件
            XSSFWorkbook excel = new XSSFWorkbook(in);
            // 获取表单页
            XSSFSheet sheet1 = excel.getSheet("Sheet1");

            // 填充数据
            // 填充数据 -- 时间
            sheet1.getRow(1).getCell(1).setCellValue("时间:" + dateBegin + "至" + dateEnd);
            // 填充数据 -- 概览
            // 获取第四行
            XSSFRow row = sheet1.getRow(3);
            // 填充营业额
            row.getCell(2).setCellValue(businessDataVO.getTurnover());
            row.getCell(4).setCellValue(businessDataVO.getOrderCompletionRate());
            row.getCell(6).setCellValue(businessDataVO.getNewUsers());
            // 获取第五行
            row = sheet1.getRow(4);
            row.getCell(2).setCellValue(businessDataVO.getValidOrderCount());
            row.getCell(4).setCellValue(businessDataVO.getUnitPrice());

            // 填充明细数据
            // 获取全部的日期
            List<LocalDate> localDateList = new ArrayList<>();
            for (LocalDate date = dateBegin; !date.isAfter(dateEnd); date = date.plusDays(1)) {
                localDateList.add(date);
            }

            // 遍历每一天
            Integer rowNum = 7;
            for (LocalDate date : localDateList) {
                // 查询当日营业数据
                businessDataVO = workspaceService.getBusinessData(LocalDateTime.of(date, LocalTime.MIN), LocalDateTime.of(date, LocalTime.MAX));
                // 获得当前行
                row = sheet1.getRow(rowNum);
                // 依次填充本行数据
                row.getCell(1).setCellValue(String.valueOf(date));
                row.getCell(2).setCellValue(businessDataVO.getTurnover());
                row.getCell(3).setCellValue(businessDataVO.getValidOrderCount());
                row.getCell(4).setCellValue(businessDataVO.getOrderCompletionRate());
                row.getCell(5).setCellValue(businessDataVO.getUnitPrice());
                row.getCell(6).setCellValue(businessDataVO.getNewUsers());
                rowNum++;
            }

            // 将文件下载到客户端浏览器
            ServletOutputStream out = response.getOutputStream();
            excel.write(out);

            // 关闭资源
            out.close();
            excel.close();

        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }


    private Map sortMap(Map<String, Integer> map, Integer num) {

        //获取entrySet
        Set<Map.Entry<String, Integer>> mapEntries = map.entrySet();

        //使用链表来对集合进行排序，使用LinkedList，利于插入元素
        List<Map.Entry<String, Integer>> result = new LinkedList<>(mapEntries);
        //自定义比较器来比较链表中的元素
        Collections.sort(result, new Comparator<Map.Entry<String, Integer>>() {
            //基于entry的值（Entry.getValue()），来排序链表
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                return o2.getValue().compareTo(o1.getValue());
            }
        });

        //将排好序的存入到LinkedHashMap(可保持顺序)中，需要存储键和值信息对到新的映射中。
        Integer sort = 1;
        Map<String, Integer> linkMap = new LinkedHashMap<>();
        for (Map.Entry<String, Integer> newEntry : result) {
            // 取出排名前5的值
            if (sort <= num) {
                linkMap.put(newEntry.getKey(), newEntry.getValue());
                ++sort;
            }
        }
        return linkMap;
    }

}
